﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;
using System.Text;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Cfg;

namespace Cloak.Work.NHibernate
{
	/// <summary>
	/// A configuration applied to NHibernate sessions
	/// </summary>
	public sealed class SessionConfiguration : ISessionConfiguration
	{
		private readonly IPersistenceConfigurer _persistenceConfigurer;
		private readonly IEnumerable<Assembly> _mappingAssemblies;

		/// <summary>
		/// Initializes a configuration with the specified persistence configurer and mapping assemblies
		/// </summary>
		/// <param name="persistenceConfigurer">Configures the persistence system</param>
		/// <param name="mappingAssemblies">Assemblies containing mapping objects</param>
		public SessionConfiguration(
			IPersistenceConfigurer persistenceConfigurer,
			IEnumerable<Assembly> mappingAssemblies)
		{
			Contract.Requires(persistenceConfigurer != null);
			Contract.Requires(mappingAssemblies != null);

			_persistenceConfigurer = persistenceConfigurer;
			_mappingAssemblies = mappingAssemblies;
		}

		/// <summary>
		/// Initializes a configuration with the specified persistence configurer and mapping assemblies
		/// </summary>
		/// <param name="persistenceConfigurer">Configures the persistence system system</param>
		/// <param name="mappingAssemblies">Assemblies containing mapping objects</param>
		public SessionConfiguration(
			IPersistenceConfigurer persistenceConfigurer,
			params Assembly[] mappingAssemblies)
			: this(persistenceConfigurer, mappingAssemblies as IEnumerable<Assembly>)
		{}

		#region ISessionConfiguration
		/// <summary>
		/// Gets an object specifying the configuration applied to NHibernate sessions
		/// </summary>
		/// <returns>An object specifying the configuration applied to NHibernate sessions</returns>
		public Configuration GetConfiguration()
		{
			return Fluently.Configure()
				.Database(_persistenceConfigurer)
				.Mappings(MapAssemblies)
				.BuildConfiguration();
		}
		#endregion

		private void MapAssemblies(MappingConfiguration mappings)
		{
			foreach(var mappingAssembly in _mappingAssemblies)
			{
				mappings.FluentMappings.AddFromAssembly(mappingAssembly);
				mappings.FluentMappings.Conventions.AddAssembly(mappingAssembly);
				mappings.HbmMappings.AddFromAssembly(mappingAssembly);
			}
		}
	}
}